package project.messagestack.utils;

import java.net.URI;
import java.security.Provider;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Vector;

import project.messagestack.network.mail.Message;
import project.messagestack.utils.UnionCursor.ColumnType;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;

public class DatabaseManager implements IDatabaseManager {
  private static SQLiteDatabase mDb;
  private Context mContext;
  private SQLiteStatement mConfigInsertStmt, mMessageInsertStmt;
  private static String mDatabaseName = "project.messagestack";
  private static int mDatabaseVersion = 1;
  private static String TABLE_CONFIGURATION = "Config";
  private static String TABLE_MESSAGES = "Messages";

  public DatabaseManager(Context context) {
    mContext = context;
    OpenHelper helper = new OpenHelper(mContext);
    mDb = helper.getWritableDatabase();
  }

  public Cursor getMessagesToDisplay() {
    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
    Vector<Cursor> cursors = new Vector<Cursor>();
    
    if (sp.getBoolean("ifSMSMMS", false)) {
      Cursor c = mContext.getContentResolver().query(Uri.parse("content://sms/inbox"),
                                                     new String[] {"_id", "\"SMS\" AS service", "date", "body", "address" },
                                                     null,
                                                     null,
                                                     "date DESC");
      cursors.add(c);
    }
    if (sp.getBoolean("ifFB", false)) {
      Cursor c = mDb.query(TABLE_MESSAGES,
                           new String[] {"_id", "serviceName AS service", "timeReceived AS date", "messageText AS body", "msgAuthor as address"},
                           "service = \"FACEBOOK\"",
                           null,
                           null,
                           null,
                           "timeReceived DESC");
      cursors.add(c);
      
    }
    if(sp.getBoolean("ifMAIL", false)){
      Cursor c = mDb.query(TABLE_MESSAGES, 
          new String[] {"_id", "serviceName AS service", "timeReceived AS date", "messageText AS body", "msgAuthor as address"},
          "service = \"MAIL\"",
          null,
          null,
          null,
          "timeReceived DESC");
          cursors.add(c);
    }

    // Dirty hack to use array instead of vector
    // casting to array with .toArray() was throwing exception
    Cursor[] k = new Cursor[cursors.size()];
    for (int i = 0; i < k.length; i++)
      k[i] = cursors.get(i);

    return new UnionCursor(k,
                           new String[] {"_id", "service", "date", "body", "address"}, 
                           new ColumnType[] {ColumnType.LONG, ColumnType.STRING, ColumnType.LONG, ColumnType.STRING, ColumnType.STRING },
                           2,
                           false);
  }
  
  public void close() {
    mDb.close();
  }
  
  public Cursor getServicesConfiguration() {
    return mDb.query(TABLE_CONFIGURATION, null, null, null, null, null, null);
  }

  public void updateConfiguration(String serviceName, URI serviceURL,
      int serviceHeldTime) {
    ContentValues values = new ContentValues();
    if (serviceURL != null) {
      values.put("serviceURL", serviceURL.toString());
    }

    if (serviceHeldTime > 0) {
      values.put("heldTime", serviceHeldTime);
    }

    if (values.size() == 0)
      return;

    if (mDb.query(TABLE_CONFIGURATION, null, "serviceName = ?",
        new String[] { serviceName }, null, null, null).getCount() == 0) {
      values.put("serviceName", serviceName);
      values.put("serviceURL", serviceURL.toString());
      values.put("heldTime", serviceHeldTime);
      mDb.insert(TABLE_CONFIGURATION, null, values);
    } else {
      mDb.update(TABLE_CONFIGURATION, values, "serviceName = ?",
          new String[] { serviceName });
    }

  }

  public boolean isExist(ContentValues values) {
    String selection = "serviceName = ? AND timeReceived = ? AND messageText = ? AND msgAuthor = ?";
    String selectionArgs[] = new String[] { values.getAsString("serviceName"),
        values.getAsString("timeReceived"), values.getAsString("messageText"),
        values.getAsString("msgAuthor") };

    if (mDb.query(TABLE_MESSAGES, null, selection, selectionArgs, null, null,
        null).getCount() == 0)
      return false;
    else
      return true;
  }

  public void addNewMessage(Message msg) {
    try {
      ContentValues values = new ContentValues();
      values.put("serviceName", msg.getType().toString());
      SimpleDateFormat sm = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
      Date d = null;

      
      d = sm.parse(msg.getReceiveDate().toString());
      Logger.logDebug(""+d.getTime())
      ;
      values.put("timeReceived", d.getTime());
      values.put("messageText", msg.getMessageBody());
      values.put("msgAuthor", msg.getSender());
      values.put("serviceName", msg.getType().toString());
      //if (!isExist(values)) {
        //Logger.logDebug("skipping msg");
        if (mDb.insert(TABLE_MESSAGES, null, values) == -1)
          Logger.logError("Error while adding msg");
      //}
    } catch (ParseException e) {
      e.printStackTrace();
    }
  }

  /**
   * Method removes all db entries older then currentTime - holdingTime
   * @param holdingTime
   *          time in ms indicating how long entries should stay in DB
   */
  public void removeOldEntries() {
    Cursor c = getServicesConfiguration();
    c.moveToFirst();
    long currentTime = new Date().getTime();
    while (c.isAfterLast()) {
      String[] s = { c.getString(c.getColumnIndex("serviceName")),
          String.valueOf(currentTime - c.getLong(c.getColumnIndex("heldTime"))) };
      mDb.delete(TABLE_MESSAGES, "serviceName = '?' AND timeReceived < ?", s);
      c.moveToNext();
    }
  }

  private static class OpenHelper extends SQLiteOpenHelper {

    public OpenHelper(Context context) {
      super(context, mDatabaseName, null, mDatabaseVersion);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
      db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_CONFIGURATION + " ( "
          + "_id INTEGER PRIMARY KEY, " + "serviceName TEXT, " + // eg. SMS, FB for icon recognition
          "serviceURL TEXT, " + // for url eg email server addr
          "heldTime UNSIGNED BIG INT " + // each service has it own holding time
          ");");

      db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_MESSAGES + " ( "
          + " _id INTEGER PRIMARY KEY ASC , " +
          " serviceName TEXT, " + // like in config table
          " timeReceived UNSIGNED BIG INT, " + // fetch time as timestamp
          " messageText TEXT, " + // msg text
          " msgAuthor TEXT " + // message author according to service
          " ); ");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVer, int newVer) {
      // no aciton is triggered on database right now
    }

  }

  public void clearAll() {
    mDb.delete(TABLE_MESSAGES, null, null);
  }

}
